import { Vector2 } from './Vector2';
import { BaseCollider } from './BaseCollider';
import {
    Collider,
    ColliderType,
    PolygonColliderOptions,
    CollisionResult
} from './types';

/**
 * 多边形碰撞体类
 */
export class PolygonCollider extends BaseCollider {
    public readonly vertices: Vector2[];
    public readonly edges: Vector2[];
    public readonly normals: Vector2[];
    
    constructor(options: PolygonColliderOptions) {
        super(options);
        
        // 确保顶点数量至少为3个
        if (options.vertices.length < 3) {
            throw new Error('Polygon must have at least 3 vertices');
        }
        
        // 克隆顶点数组
        this.vertices = options.vertices.map(v => v.clone());
        
        // 计算边和法线
        this.edges = [];
        this.normals = [];
        this.updateEdgesAndNormals();
        
        this.updateBounds();
    }
    
    /**
     * 检查是否与另一个碰撞体相交
     */
    public intersects(other: Collider): boolean {
        if (!this.canCollideWith(other)) {
            return false;
        }
        
        switch (other.type) {
            case ColliderType.RECTANGLE:
                return this.intersectsRectangle(other);
            case ColliderType.CIRCLE:
                return this.intersectsCircle(other);
            case ColliderType.POLYGON:
                return this.intersectsPolygon(other as PolygonCollider);
            default:
                return false;
        }
    }
    
    /**
     * 检查点是否在碰撞体内
     */
    public contains(point: Vector2): boolean {
        const local = this.worldToLocal(point);
        
        // 使用射线法判断点是否在多边形内部
        let inside = false;
        for (let i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
            const xi = this.vertices[i].x;
            const yi = this.vertices[i].y;
            const xj = this.vertices[j].x;
            const yj = this.vertices[j].y;
            
            const intersect = ((yi > local.y) !== (yj > local.y)) &&
                (local.x < (xj - xi) * (local.y - yi) / (yj - yi) + xi);
            if (intersect) {
                inside = !inside;
            }
        }
        
        return inside;
    }
    
    /**
     * 获取碰撞体中心点
     */
    public getCenter(): Vector2 {
        const center = new Vector2();
        for (const vertex of this.vertices) {
            center.add(vertex);
        }
        return center.divide(this.vertices.length).add(this.offset);
    }
    
    /**
     * 获取碰撞体面积
     */
    public getArea(): number {
        let area = 0;
        for (let i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
            area += this.vertices[i].x * this.vertices[j].y;
            area -= this.vertices[j].x * this.vertices[i].y;
        }
        return Math.abs(area / 2) * this.scale.x * this.scale.y;
    }
    
    /**
     * 克隆碰撞体
     */
    public clone(): PolygonCollider {
        return new PolygonCollider({
            type: ColliderType.POLYGON,
            vertices: this.vertices.map(v => v.clone()),
            isTrigger: this.isTrigger,
            tag: this.tag,
            layer: this.layer,
            offset: this.offset.clone(),
            rotation: this.rotation,
            scale: this.scale.clone(),
            enabled: this.enabled
        });
    }
    
    /**
     * 更新碰撞体边界
     */
    protected updateBounds(): void {
        if (this.vertices.length === 0) {
            this.bounds.min = new Vector2();
            this.bounds.max = new Vector2();
            return;
        }
        
        let minX = Infinity;
        let minY = Infinity;
        let maxX = -Infinity;
        let maxY = -Infinity;
        
        for (const vertex of this.vertices) {
            const worldPos = this.localToWorld(vertex);
            minX = Math.min(minX, worldPos.x);
            minY = Math.min(minY, worldPos.y);
            maxX = Math.max(maxX, worldPos.x);
            maxY = Math.max(maxY, worldPos.y);
        }
        
        this.bounds.min = new Vector2(minX, minY);
        this.bounds.max = new Vector2(maxX, maxY);
    }
    
    /**
     * 计算两个碰撞体之间的碰撞结果
     */
    protected calculateCollision(other: Collider): CollisionResult {
        switch (other.type) {
            case ColliderType.RECTANGLE:
                return this.calculateRectangleCollision(other);
            case ColliderType.CIRCLE:
                return this.calculateCircleCollision(other);
            case ColliderType.POLYGON:
                return this.calculatePolygonCollision(other as PolygonCollider);
            default:
                return { collided: false };
        }
    }
    
    /**
     * 更新边和法线
     */
    private updateEdgesAndNormals(): void {
        this.edges.length = 0;
        this.normals.length = 0;
        
        for (let i = 0; i < this.vertices.length; i++) {
            const current = this.vertices[i];
            const next = this.vertices[(i + 1) % this.vertices.length];
            
            // 计算边向量
            const edge = next.clone().subtract(current);
            this.edges.push(edge);
            
            // 计算法线向量（垂直于边，指向多边形外部）
            const normal = new Vector2(-edge.y, edge.x).normalized;
            this.normals.push(normal);
        }
    }
    
    /**
     * 检查是否与矩形碰撞体相交
     */
    private intersectsRectangle(other: Collider): boolean {
        const result = this.calculateRectangleCollision(other);
        return result.collided;
    }
    
    /**
     * 检查是否与圆形碰撞体相交
     */
    private intersectsCircle(other: Collider): boolean {
        const result = this.calculateCircleCollision(other);
        return result.collided;
    }
    
    /**
     * 检查是否与多边形碰撞体相交
     */
    private intersectsPolygon(other: PolygonCollider): boolean {
        const result = this.calculatePolygonCollision(other);
        return result.collided;
    }
    
    /**
     * 计算与矩形碰撞体的碰撞结果
     */
    private calculateRectangleCollision(other: Collider): CollisionResult {
        // 将矩形的四个顶点转换为多边形
        const rectVertices = [
            new Vector2(-(other as any).halfWidth, -(other as any).halfHeight),
            new Vector2((other as any).halfWidth, -(other as any).halfHeight),
            new Vector2((other as any).halfWidth, (other as any).halfHeight),
            new Vector2(-(other as any).halfWidth, (other as any).halfHeight)
        ].map(v => (other as any).localToWorld(v));
        
        // 使用SAT算法检测碰撞
        const axes = [...this.normals, ...rectVertices.map((v, i) => {
            const next = rectVertices[(i + 1) % rectVertices.length];
            return new Vector2(-(next.y - v.y), next.x - v.x).normalized;
        })];
        
        let minOverlap = Infinity;
        let collisionNormal = new Vector2();
        
        for (const axis of axes) {
            const proj1 = this.projectVertices(axis);
            const proj2 = this.projectVertices(axis, rectVertices);
            
            const overlap = Math.min(proj1.max - proj2.min, proj2.max - proj1.min);
            
            if (overlap <= 0) {
                return { collided: false };
            }
            
            if (overlap < minOverlap) {
                minOverlap = overlap;
                collisionNormal = axis;
            }
        }
        
        // 确保法线指向正确的方向
        const centerDiff = other.getCenter().subtract(this.getCenter());
        if (centerDiff.dot(collisionNormal) < 0) {
            collisionNormal = collisionNormal.negate();
        }
        
        // 找到碰撞点
        const contactPoint = this.findContactPoint(rectVertices, collisionNormal);
        
        return {
            collided: true,
            contactPoint,
            normal: collisionNormal,
            penetration: minOverlap
        };
    }
    
    /**
     * 计算与圆形碰撞体的碰撞结果
     */
    private calculateCircleCollision(other: Collider): CollisionResult {
        const circleCenter = other.getCenter();
        const circleRadius = (other as any).radius * (other as any).scale.x;
        
        // 找到多边形上距离圆心最近的点
        let minDistance = Infinity;
        let closestPoint = new Vector2();
        let closestNormal = new Vector2();
        
        for (let i = 0; i < this.vertices.length; i++) {
            const start = this.localToWorld(this.vertices[i]);
            const end = this.localToWorld(this.vertices[(i + 1) % this.vertices.length]);
            const edge = end.subtract(start);
            const edgeLength = edge.length;
            const edgeNormal = this.normals[i];
            
            // 计算圆心到边的距离
            const toCircle = circleCenter.subtract(start);
            const projection = toCircle.dot(edge) / edgeLength;
            const closest = start.clone().add(edge.clone().multiply(Math.max(0, Math.min(1, projection / edgeLength))));
            const distance = circleCenter.distance(closest);
            
            if (distance < minDistance) {
                minDistance = distance;
                closestPoint = closest;
                closestNormal = edgeNormal;
            }
        }
        
        // 检查是否发生碰撞
        if (minDistance > circleRadius) {
            return { collided: false };
        }
        
        // 计算碰撞法线和穿透深度
        const normal = circleCenter.subtract(closestPoint).normalized;
        const penetration = circleRadius - minDistance;
        
        return {
            collided: true,
            contactPoint: closestPoint,
            normal,
            penetration
        };
    }
    
    /**
     * 计算与多边形碰撞体的碰撞结果
     */
    private calculatePolygonCollision(other: PolygonCollider): CollisionResult {
        // 使用SAT算法检测碰撞
        const axes = [...this.normals, ...other.normals];
        
        let minOverlap = Infinity;
        let collisionNormal = new Vector2();
        
        for (const axis of axes) {
            const proj1 = this.projectVertices(axis);
            const proj2 = this.projectVertices(axis, other.vertices.map(v => other.localToWorld(v)));
            
            const overlap = Math.min(proj1.max - proj2.min, proj2.max - proj1.min);
            
            if (overlap <= 0) {
                return { collided: false };
            }
            
            if (overlap < minOverlap) {
                minOverlap = overlap;
                collisionNormal = axis;
            }
        }
        
        // 确保法线指向正确的方向
        const centerDiff = other.getCenter().subtract(this.getCenter());
        if (centerDiff.dot(collisionNormal) < 0) {
            collisionNormal = collisionNormal.negate();
        }
        
        // 找到碰撞点
        const contactPoint = this.findContactPoint(other.vertices.map(v => other.localToWorld(v)), collisionNormal);
        
        return {
            collided: true,
            contactPoint,
            normal: collisionNormal,
            penetration: minOverlap
        };
    }
    
    /**
     * 将顶点投影到指定轴上
     */
    private projectVertices(axis: Vector2, vertices: Vector2[] = this.vertices.map(v => this.localToWorld(v))): { min: number; max: number } {
        let min = axis.dot(vertices[0]);
        let max = min;
        
        for (let i = 1; i < vertices.length; i++) {
            const projection = axis.dot(vertices[i]);
            min = Math.min(min, projection);
            max = Math.max(max, projection);
        }
        
        return { min, max };
    }
    
    /**
     * 找到碰撞点
     */
    private findContactPoint(otherVertices: Vector2[], normal: Vector2): Vector2 {
        // 找到两个多边形上距离碰撞法线最远的点
        let maxDist = -Infinity;
        let contactPoint = new Vector2();
        
        // 检查当前多边形的顶点
        for (const vertex of this.vertices) {
            const worldPos = this.localToWorld(vertex);
            const dist = normal.dot(worldPos);
            if (dist > maxDist) {
                maxDist = dist;
                contactPoint = worldPos;
            }
        }
        
        // 检查另一个多边形的顶点
        for (const vertex of otherVertices) {
            const dist = normal.dot(vertex);
            if (dist > maxDist) {
                maxDist = dist;
                contactPoint = vertex;
            }
        }
        
        return contactPoint;
    }
} 